/*
  XXX does not use built-in detection function! XXX
  
alert tcp $EXTERNAL_NET any -> $HOME_NET $HTTP_PORTS (msg:"DOS Microsoft ASP.NET viewstate DoS attempt"; flow:to_server,established,only_stream; content:"__VIEWSTATE="; metadata:policy balanced-ips drop, policy security-ips drop, service http; reference:cve,2005-1665; reference:url,osvdb.org/show/osvdb/16195; classtype:attempted-dos; sid:15959; rev:2;)
 */
/*
 * Vuln Title: Microsoft ASP.NET ViewState Denial of Service
 *
 * Copyright (C) 2005-2010 Sourcefire, Inc. All Rights Reserved
 *
 * Written by Sojeong Hong, Sourcefire VRT <shong@sourcefire.com>
 *
 * Auto-generated by shong
 *
 * This file may contain proprietary rules that were created, tested and
 * certified by Sourcefire, Inc. (the "VRT Certified Rules") as well as
 * rules that were created by Sourcefire and other third parties and
 * distributed under the GNU General Public License (the "GPL Rules").  The
 * VRT Certified Rules contained in this file are the property of
 * Sourcefire, Inc. Copyright 2005 Sourcefire, Inc. All Rights Reserved.
 * The GPL Rules created by Sourcefire, Inc. are the property of
 * Sourcefire, Inc. Copyright 2002-2005 Sourcefire, Inc. All Rights
 * Reserved.  All other GPL Rules are owned and copyrighted by their
 * respective owners (please see www.snort.org/contributors for a list of
 * owners and their respective copyrights).  In order to determine what
 * rules are VRT Certified Rules or GPL Rules, please refer to the VRT
 * Certified Rules License Agreement.
 */

#include "sf_snort_plugin_api.h"
#include "sf_snort_packet.h"
#include "so-util_base64-decode.h"

//#define DEBUG 1
#ifdef DEBUG
#define DEBUG_SO(code) code
#else
#define DEBUG_SO(code)
#endif

/* declare detection functions */
int rule15959eval(void *p);

/* declare rule data structures */
/* flow:established, only_stream, to_server; */
static FlowFlags rule15959flow0 = 
{
    FLOW_ESTABLISHED|FLOW_ONLY_REASSMBLED|FLOW_TO_SERVER
};

static RuleOption rule15959option0 =
{
    OPTION_TYPE_FLOWFLAGS,
    {
        &rule15959flow0
    }
};
// content:"__VIEWSTATE=", depth 0, fast_pattern; 
static ContentInfo rule15959content1 = 
{
    (uint8_t *) "__VIEWSTATE=", /* pattern (now in snort content format) */
    0, /* depth */
    0, /* offset */
    CONTENT_FAST_PATTERN|CONTENT_BUF_NORMALIZED, /* flags */
    NULL, /* holder for boyer/moore PTR */
    NULL, /* more holder info - byteform */
    0, /* byteform length */
    0 /* increment length*/
};

static RuleOption rule15959option1 = 
{
    OPTION_TYPE_CONTENT,
    {
        &rule15959content1
    }
};

/* references for sid 15959 */
/* reference: cve "2005-1665"; */
static RuleReference rule15959ref1 = 
{
    "cve", /* type */
    "2005-1665" /* value */
};

/* reference: url "osvdb.org/show/osvdb/16195"; */
static RuleReference rule15959ref2 = 
{
    "url", /* type */
    "osvdb.org/show/osvdb/16195" /* value */
};

static RuleReference *rule15959refs[] =
{
    &rule15959ref1,
    &rule15959ref2,
    NULL
};
/* metadata for sid 15959 */
/* metadata:service http, policy balanced-ips drop, policy security-ips drop; */
static RuleMetaData rule15959service1 = 
{
    "service http"
};


static RuleMetaData rule15959policy1 = 
{
    "policy balanced-ips drop"
};

static RuleMetaData rule15959policy2 = 
{
    "policy security-ips drop"
};

static RuleMetaData rule15959policy3 = 
{
    "policy max-detect-ips drop"
};

static RuleMetaData *rule15959metadata[] =
{
    &rule15959service1,
    &rule15959policy1,
    &rule15959policy2,
    &rule15959policy3,
    NULL
};

RuleOption *rule15959options[] =
{
    &rule15959option0,
    &rule15959option1,
    NULL
};

Rule rule15959 = {
   /* rule header, akin to => tcp any any -> any any */
   {
       IPPROTO_TCP, /* proto */
       "$EXTERNAL_NET", /* SRCIP     */
       "any", /* SRCPORT   */
       0, /* DIRECTION */
       "$HOME_NET", /* DSTIP     */
       "$HTTP_PORTS", /* DSTPORT   */
   },
   /* metadata */
   { 
       3,  /* genid */
       15959, /* sigid */
       5, /* revision */
       "attempted-dos", /* classification */
       0,  /* hardcoded priority XXX NOT PROVIDED BY GRAMMAR YET! */
       "SERVER-IIS Microsoft ASP.NET viewstate DoS attempt",     /* message */
       rule15959refs /* ptr to references */
       ,rule15959metadata
   },
   rule15959options, /* ptr to rule options */
   &rule15959eval, /* use the built in detection function */
   0 /* am I initialized yet? */
};

/* detection functions */
int rule15959eval(void *p) {    
    const uint8_t *cursor = 0;
    SFSnortPacket *sp = (SFSnortPacket *) p;

    const uint8_t *beg_of_buffer, *end_of_buffer;
    uint8_t decodedbuf[1024];
    uint32_t i, decodedbytes;
    int32_t nest_level = 0;

    DEBUG_SO(printf("enter rule15959eval\n");)
        
    if(sp == NULL)
        return RULE_NOMATCH;

    if(sp->payload == NULL)
        return RULE_NOMATCH;
    
    // flow:established, to_server;
    if (checkFlow(p, rule15959options[0]->option_u.flowFlags) <= 0 ) 
        return RULE_NOMATCH;
    
    // content:"__VIEWSTATE=", depth 0, fast_pattern;
    if (contentMatch(p, rule15959options[1]->option_u.content, &cursor) <= 0) 
        return RULE_NOMATCH;

    if(getBuffer(sp, CONTENT_BUF_NORMALIZED, &beg_of_buffer, &end_of_buffer) != CURSOR_IN_BOUNDS)
        return RULE_NOMATCH;

    DEBUG_SO(printf("found \"__VIEWSTATE=\"\n");)

    if(base64decode(cursor, (end_of_buffer - cursor), decodedbuf, sizeof(decodedbuf), &decodedbytes) < 0)
        return RULE_NOMATCH;

    DEBUG_SO(printf("Successfully base64 decoded (%s)(%d)\n", decodedbuf, decodedbytes);)
                 
    for (i = 0; i < decodedbytes; i++)
    {            
        if (decodedbuf[i] == '<')
            nest_level++;
        else if (decodedbuf[i] == '>' && nest_level > 0)
            nest_level--;

        if (nest_level > 500)
        {
            DEBUG_SO(printf("nest_level [%d]\n", nest_level);)
            return RULE_MATCH;
        }
    }
    
    return RULE_NOMATCH;
}
/*
Rule *rules[] = {
    &rule15959,
    NULL
};
*/
